using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Web;
using Payroll.BusinessLogic.Caching;
using Payroll.BusinessLogic.Configuration;
using Payroll.BusinessLogic.Configuration.Settings;
using Payroll.BusinessLogic.Data;
using Payroll.BusinessLogic.Directory;
using Payroll.BusinessLogic.Infrastructure;
using Payroll.Common.Utils;
using Payroll.BusinessLogic.CustomerManager;
using Payroll.BusinessLogic.Audit;
using Payroll.BusinessLogic.ExportImport;
using Payroll.BusinessLogic.Company;
using System.Net.Mime;
using Payroll.BusinessLogic.Security;

namespace Payroll.BusinessLogic.Messages
{
    /// <summary>
    /// Message service
    /// </summary>
    public partial class MessageService : IMessageService
    {
        #region Fields

        /// <summary>
        /// Object context
        /// </summary>
        private readonly PayrollHRDataContext _context;
        /// <summary>
        /// Cache manager
        /// </summary>
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="context">Object context</param>
        public MessageService(PayrollHRDataContext context)
        {
            this._context = context;
            this._cacheManager = new PayrollRequestCache();
        }

        #endregion
        public void UpdateQueuedEmail(QueuedEmail queuedEmail)
        {
            if (queuedEmail == null)
                throw new ArgumentNullException("queuedEmail");
            var item = (from qe in _context.QueuedEmails
                        where qe.QueuedEmailID == queuedEmail.QueuedEmailId
                        select qe).FirstOrDefault();
            if (!CommonHelper.IsNull(item))
            {
                item.From = CommonHelper.EnsureNotNull(queuedEmail.From);
                item.From = CommonHelper.EnsureMaximumLength(queuedEmail.From, 500);
                item.FromName = CommonHelper.EnsureNotNull(queuedEmail.FromName);
                item.FromName = CommonHelper.EnsureMaximumLength(queuedEmail.FromName, 500);
                item.To = CommonHelper.EnsureNotNull(queuedEmail.To);
                item.To = CommonHelper.EnsureMaximumLength(queuedEmail.To, 500);
                item.ToName = CommonHelper.EnsureNotNull(queuedEmail.ToName);
                item.ToName = CommonHelper.EnsureMaximumLength(queuedEmail.ToName, 500);
                item.Cc = CommonHelper.EnsureNotNull(queuedEmail.CC);
                item.Cc = CommonHelper.EnsureMaximumLength(queuedEmail.CC, 500);
                item.Bcc = CommonHelper.EnsureNotNull(queuedEmail.Bcc);
                item.Bcc = CommonHelper.EnsureMaximumLength(queuedEmail.Bcc, 500);
                item.Subject = CommonHelper.EnsureNotNull(queuedEmail.Subject);
                item.Subject = CommonHelper.EnsureMaximumLength(queuedEmail.Subject, 500);
                item.Body = CommonHelper.EnsureNotNull(queuedEmail.Body);
                item.SentOn = queuedEmail.SentOn;
                item.FileAttachment = queuedEmail.FileAttachment;
                item.SendTries = queuedEmail.SendTries;
                _context.SubmitChanges();
            }
        }
        protected Data.QueuedEmail Tranffer(QueuedEmail queuedEmail)
        {
            return new Data.QueuedEmail
            {
                Priority = queuedEmail.Priority,
                From = queuedEmail.From,
                FromName = queuedEmail.FromName,
                To = queuedEmail.To,
                ToName = queuedEmail.ToName,
                Cc = queuedEmail.CC,
                Bcc = queuedEmail.Bcc,
                Subject = queuedEmail.Subject,
                Body = queuedEmail.Body,
                CreatedOn = queuedEmail.CreatedOn,
                SendTries = queuedEmail.SendTries,
                SentOn = queuedEmail.SentOn,
                EmailAccountId = queuedEmail.EmailAccountId,
                FileAttachment = queuedEmail.FileAttachment
            };
        }
        public List<QueuedEmail> GetAllQueuedEmails(int queuedEmailCount,
            bool loadNotSentItemsOnly, int maxSendTries)
        {
            return GetAllQueuedEmails(string.Empty, string.Empty, null, null,
                queuedEmailCount, loadNotSentItemsOnly, maxSendTries);
        }
        public List<QueuedEmail> GetAllQueuedEmails(string fromEmail,
            string toEmail, DateTime? startTime, DateTime? endTime,
            int queuedEmailCount, bool loadNotSentItemsOnly, int maxSendTries)
        {
            if (fromEmail == null)
                fromEmail = string.Empty;
            fromEmail = fromEmail.Trim();

            if (toEmail == null)
                toEmail = string.Empty;
            toEmail = toEmail.Trim();

            var query = from qe in _context.QueuedEmails
                        select new QueuedEmail
                        {
                            QueuedEmailId = qe.QueuedEmailID,
                            Priority = qe.Priority,
                            From = qe.From,
                            FromName = qe.FromName,
                            To = qe.To,
                            ToName = qe.ToName,
                            CC = qe.Cc,
                            Bcc = qe.Bcc,
                            Subject = qe.Subject,
                            Body = qe.Body,
                            CreatedOn = qe.CreatedOn,
                            SendTries = qe.SendTries,
                            SentOn = qe.SentOn,
                            EmailAccountId = qe.EmailAccountId,
                            FileAttachment = qe.FileAttachment
                        };

            if (!String.IsNullOrEmpty(fromEmail))
                query = query.Where(qe => qe.From.Contains(fromEmail));
            if (!String.IsNullOrEmpty(toEmail))
                query = query.Where(qe => qe.To.Contains(toEmail));
            if (startTime.HasValue)
                query = query.Where(qe => startTime.Value <= qe.CreatedOn);
            if (endTime.HasValue)
                query = query.Where(qe => endTime.Value >= qe.CreatedOn);
            if (loadNotSentItemsOnly)
                query = query.Where(qe => !qe.SentOn.HasValue);
            query = query.Where(qe => qe.SendTries < maxSendTries);
            if (queuedEmailCount > 0)
                query = query.Take(queuedEmailCount);
            query = query.OrderByDescending(qe => qe.Priority).ThenBy(qe => qe.CreatedOn);

            var queuedEmails = query.ToList();

            return queuedEmails;
        }
        #region Utilities

        private string Replace(string original, string pattern, string replacement)
        {
            if (IoC.Resolve<ISettingManager>().GetSettingValueBoolean("MessageTemplates.CaseInvariantReplacement"))
            {
                int count = 0;
                int position0 = 0;
                int position1 = 0;
                string upperString = original.ToUpper();
                string upperPattern = pattern.ToUpper();
                int inc = (original.Length / pattern.Length) * (replacement.Length - pattern.Length);
                char[] chars = new char[original.Length + Math.Max(0, inc)];
                while ((position1 = upperString.IndexOf(upperPattern, position0)) != -1)
                {
                    for (int i = position0; i < position1; ++i)
                        chars[count++] = original[i];
                    for (int i = 0; i < replacement.Length; ++i)
                        chars[count++] = replacement[i];
                    position0 = position1 + pattern.Length;
                }
                if (position0 == 0) return original;
                for (int i = position0; i < original.Length; ++i)
                    chars[count++] = original[i];
                return new string(chars, 0, count);
            }
            else
            {
                return original.Replace(pattern, replacement);
            }
        }

        #endregion

        #region Methods

        #region Repository methods

        #endregion

        #region Workflow methods


        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body, string from, string to,
            EmailAccounts emailAccount)
        {
            SendEmail(subject, body, new MailAddress(from), new MailAddress(to),
                new List<String>(), new List<String>(), emailAccount);
        }
        /// <summary>
        /// Sends the email.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="body">The body.</param>
        /// <param name="from">From.</param>
        /// <param name="to">To.</param>
        /// <param name="fileAttachment">The file attachment.</param>
        /// <param name="emailAccount">The email account.</param>
        public void SendEmail(string subject, string body, string from, string to, List<string> fileAttachment,
            EmailAccounts emailAccount)
        {
            SendEmail(subject, body, new MailAddress(from), new MailAddress(to),
                new List<String>(), new List<String>(), fileAttachment, emailAccount);
        }
        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body, MailAddress from,
            MailAddress to, EmailAccounts emailAccount)
        {
            SendEmail(subject, body, from, to, new List<String>(), new List<String>(), emailAccount);
        }

        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="bcc">BCC</param>
        /// <param name="cc">CC</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body,
            MailAddress from, MailAddress to, List<string> bcc,
            List<string> cc, EmailAccounts emailAccount)
        {
            var message = new MailMessage();
            message.From = from;
            message.To.Add(to);
            if (null != bcc)
                foreach (string address in bcc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.Bcc.Add(address.Trim());
                        }
                    }
                }
            if (null != cc)
                foreach (string address in cc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.CC.Add(address.Trim());
                        }
                    }
                }
            message.Subject = subject;
            message.Body = body;
            message.IsBodyHtml = true;

            var smtpClient = new SmtpClient();
            smtpClient.UseDefaultCredentials = emailAccount.UseDefaultCredentials;
            smtpClient.Host = emailAccount.Host;
            smtpClient.Port = emailAccount.Port;
            smtpClient.EnableSsl = emailAccount.EnableSSL;
            if (emailAccount.UseDefaultCredentials)
                smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials;
            else
                smtpClient.Credentials = new NetworkCredential(emailAccount.Username, emailAccount.Password);
            smtpClient.Send(message);
        }
        /// <summary>
        /// Sends the email.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="body">The body.</param>
        /// <param name="from">From.</param>
        /// <param name="to">To.</param>
        /// <param name="bcc">The BCC.</param>
        /// <param name="cc">The cc.</param>
        /// <param name="fileAttachment">The file attachment.</param>
        /// <param name="emailAccount">The email account.</param>
        public void SendEmail(string subject, string body,
            MailAddress from, MailAddress to, List<string> bcc,
            List<string> cc, List<string> fileAttachment, EmailAccounts emailAccount)
        {
            var message = new MailMessage();
            message.From = from;
            message.To.Add(to);
            if (null != bcc)
                foreach (string address in bcc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.Bcc.Add(address.Trim());
                        }
                    }
                }
            if (null != cc)
                foreach (string address in cc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.CC.Add(address.Trim());
                        }
                    }
                }
            if (null != fileAttachment)
            {
                foreach (string attachment in fileAttachment)
                {
                    if (attachment != null)
                    {
                        if (!String.IsNullOrEmpty(attachment.Trim()))
                        {
                            // Add the file attachment to this e-mail message.
                            message.Attachments.Add(new Attachment(attachment, MediaTypeNames.Application.Octet));
                        }
                    }
                }
            }
            message.Subject = subject;
            message.Body = body;
            message.IsBodyHtml = true;

            var smtpClient = new SmtpClient();
            smtpClient.UseDefaultCredentials = emailAccount.UseDefaultCredentials;
            smtpClient.Host = emailAccount.Host;
            smtpClient.Port = emailAccount.Port;
            smtpClient.EnableSsl = emailAccount.EnableSSL;
            if (emailAccount.UseDefaultCredentials)
                smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials;
            else
                smtpClient.Credentials = new NetworkCredential(emailAccount.Username, emailAccount.Password);
            smtpClient.Send(message);
        }
        #endregion

        #endregion

        #region Properties
        #region email account
        public EmailAccounts DefaultEmailAccount
        {
            get
            {
                int defaultEmailAccountId = IoC.Resolve<ISettingManager>().GetSettingValueInteger("EmailAccount.DefaultEmailAccountId");
                var emailAccount = GetEmailAccountById(defaultEmailAccountId);
                if (emailAccount == null)
                    emailAccount = GetAllEmailAccounts().FirstOrDefault();

                return emailAccount;
            }
            set
            {
                if (value != null)
                    IoC.Resolve<ISettingManager>().SetParam("EmailAccount.DefaultEmailAccountId", value.EmailAccountId.ToString());
            }
        }
        public EmailAccounts GetEmailAccountById(int emailAccountId)
        {
            if (emailAccountId == 0)
                return null;
            var query = from ea in _context.EmailAccounts
                        where ea.EmailAccountId == emailAccountId
                        select new EmailAccounts
                        {
                            EmailAccountId = ea.EmailAccountId,
                            Email = ea.Email,
                            DisplayName = ea.DisplayName,
                            Host = ea.Host,
                            Port = ea.Port,
                            Username = ea.Username,
                            Password = SecurityHelper.Decrypt(ea.Password),
                            EnableSSL = ea.EnableSSL,
                            UseDefaultCredentials = ea.UseDefaultCredentials
                        };
            var emailAccount = query.SingleOrDefault();
            return emailAccount;
        }
        public string DefaultMailSend
        {
            get
            {
                var query = (from mc in _context.MyCompanies
                             select mc).FirstOrDefault();
                return query.EmailSender;
            }
        }
        public List<EmailAccounts> GetAllEmailAccounts()
        {
            var query = from ea in _context.EmailAccounts
                        orderby ea.EmailAccountId
                        select new EmailAccounts
                        {
                            EmailAccountId = ea.EmailAccountId,
                            Email = ea.Email,
                            DisplayName = ea.DisplayName,
                            Host = ea.Host,
                            Port = ea.Port,
                            Username = ea.Username,
                            Password = SecurityHelper.Decrypt(ea.Password),
                            EnableSSL = ea.EnableSSL,
                            UseDefaultCredentials = ea.UseDefaultCredentials
                        };

            var emailAccounts = query.ToList();

            return emailAccounts;
        }

        public string MailSend
        {
            get
            {
                int defaultEmailAccountId = IoC.Resolve<ISettingManager>().GetSettingValueInteger("EmailAccount.DefaultEmailAccountId");
                var emailAccount = GetEmailAccountById(defaultEmailAccountId);
                if (emailAccount == null)
                    emailAccount = GetAllEmailAccounts().FirstOrDefault();

                return emailAccount.Email;
            }
        }
        public void SaveEmailAccounts(EmailAccounts emailAccount)
        {
            var item = (from e in _context.EmailAccounts
                        where e.EmailAccountId == emailAccount.EmailAccountId
                        select e).FirstOrDefault();
            if (!CommonHelper.IsNull(item))
            {
                item.Email = emailAccount.Email;
                item.DisplayName = emailAccount.DisplayName;
                item.Host = emailAccount.Host;
                item.Port = emailAccount.Port;
                item.Username = emailAccount.Username;
                item.Password = SecurityHelper.Encrypt(emailAccount.Password);
                item.EnableSSL = emailAccount.EnableSSL;
                item.UseDefaultCredentials = emailAccount.UseDefaultCredentials;
            }
            else
            {
                _context.EmailAccounts.InsertOnSubmit(new Data.EmailAccount
                {
                    Email = emailAccount.Email,
                    DisplayName = emailAccount.DisplayName,
                    Host = emailAccount.Host,
                    Port = emailAccount.Port,
                    Username = emailAccount.Username,
                    Password = SecurityHelper.Encrypt(emailAccount.Password),
                    EnableSSL = emailAccount.EnableSSL,
                    UseDefaultCredentials = emailAccount.UseDefaultCredentials
                });
            }
            _context.SubmitChanges();
        }
        public EmailAccounts GetEmailAccounts()
        {
            var item = (from e in _context.EmailAccounts
                        select new EmailAccounts
                        {
                            EmailAccountId = e.EmailAccountId,
                            Email = e.Email,
                            DisplayName = e.DisplayName,
                            Host = e.Host,
                            Port = e.Port,
                            Username = e.Username,
                            Password = SecurityHelper.Decrypt(e.Password),
                            EnableSSL = e.EnableSSL,
                            UseDefaultCredentials = e.UseDefaultCredentials
                        }).FirstOrDefault();
            return item;
        }
        #endregion
        #endregion
        public void SaveQueuedEmail(QueuedEmail queuedEmail, string MessageId)
        {
            try
            {
                using (var scope = new System.Transactions.TransactionScope())
                {
                    _context.QueuedEmails.InsertOnSubmit(this.Tranffer(queuedEmail));
                    _context.MessageMail_UpdateStatus(messageID: MessageId);

                    _context.SubmitChanges();

                    scope.Complete();
                }
            }
            catch (Exception exc)
            {
                IoC.Resolve<ILogService>().InsertLog(LogTypeEnum.MailError, string.Format("Error saving queued. {0}", exc.Message), exc);
            }
        }
        public void SaveQueuedEmail(QueuedEmail queuedEmail)
        {
            try
            {
                _context.QueuedEmails.InsertOnSubmit(this.Tranffer(queuedEmail));
                _context.SubmitChanges();
            }
            catch (Exception exc)
            {
                IoC.Resolve<ILogService>().InsertLog(LogTypeEnum.MailError, string.Format("Error saving queued. {0}", exc.Message), exc);
            }
        }

        public void SaveQueuedEmail(string MessageId, string PhysicalApplicationPath)
        {
            var query = this.GetQueuedEmails(MessageId);
            var queryAttachColection = this.GetAttachmentByMessageID(MessageID: MessageId);

            string fileName = string.Format("DE_NGHI_CAP_CKS{0}_{1}.xlsx", DateTime.Now.ToString("yyyyMMdd-HHmmss"), CommonHelper.GenerateRandomDigitCode(4));

            string filePath = string.Format("{0}Administration\\FileExport\\{1}", PhysicalApplicationPath, fileName);

            string filetemplate = string.Format("{0}Administration\\Template\\{1}", PhysicalApplicationPath, "template.xlsx");

            int priority = 1;

            EmailAccounts account = IoC.Resolve<IMessageService>().DefaultEmailAccount;

            ExcelHelper.ExportSendMailExcel(query, ref filePath, filetemplate);

            if (queryAttachColection.Length > 0)
            {
                filePath += queryAttachColection;
            }
            QueuedEmail queuedEmails = new QueuedEmail
            {
                Priority = priority,
                From = account.Email,
                FromName = "DE NGHI CAP CKS - CNHCM",
                To = PayrollConfig.MailSend,
                ToName = account.FriendlyName,
                EmailAccountId = 1,
                CC = "",
                Bcc = "",
                Subject = "DE NGHI CAP CKS - CNHCM",
                Body = "DE NGHI CAP CKS - CNHCM",
                CreatedOn = DateTime.Now,
                SendTries = 0,
                SentOn = null,
                QueuedEmailId = 1,
                FileAttachment = filePath
            };
            IoC.Resolve<IMessageService>().SaveQueuedEmail(queuedEmails, MessageId);
            priority += 1;
        }
        /// <summary>
        /// Gets the queued emails.
        /// </summary>
        /// <param name="MessageId">The message id.</param>
        /// <returns></returns>
        private List<Results> GetQueuedEmails(string MessageId)
        {
            var query = (from r in _context.Results_GetQueuedEmails(messageId: MessageId)
                         select new Results
                         {
                             ResultsId = r.ResultsId,
                             PackageCode = r.PackageCode,
                             DatePurchase = r.DatePurchase,
                             CustomerName = r.CustomerName,
                             TaxCode = r.TaxCode,
                             Address = r.Address,
                             Mobile = r.Mobile,
                             Email = r.Email,
                             ServiceFree = r.ServiceFree,
                             CustomerProfile = r.CustomerProfile,
                         }).ToList();
            return query;
        }
        /// <summary>
        /// Gets the by message ID.
        /// </summary>
        /// <param name="MessageID">The message ID.</param>
        /// <returns></returns>
        private List<MessageMail> GetByMessageID(string MessageID)
        {
            return (from mm in _context.MessageMail_GetByMessageID(messageID: MessageID)
                    select new MessageMail
                    {
                        MessageID = mm.MessageID,
                        attachment = mm.attachment,
                        Frommail = mm.Frommail
                    }
                        ).ToList();
        }
        private string GetAttachmentByMessageID(string MessageID)
        {
            string fileAttach = "";
            var query = this.GetByMessageID(MessageID: MessageID);
            foreach (var mm in query)
            {
                if (!CommonHelper.IsNull(mm.attachment))
                {
                    fileAttach += ";" + mm.attachment;
                }
            }
            return fileAttach;
        }
        public List<MessageMails> GetMessge(string packageCode = null, string fromdate = null, string todate = null, string Distributor = null, string customerName = null, string taxcode = null, string mobile = null, string email = null, int? confrim = 3, int pageSize = int.MaxValue, int pageIndex = 0)
        {
            var query = from mm in _context.MessageMail_GetDynamicContents(packageCode: packageCode, fromdate: fromdate, todate: todate, distributor: Distributor, custName: customerName, taxcode: taxcode, mobile: mobile, email: email, confirm: confrim.Value)
                        select new MessageMails
                        {
                            MessageID = mm.MessageID,
                            Body = mm.Body,
                            attachment = mm.attachment,
                            ResDateReceive = mm.ResDateReceive,
                            Frommail = mm.Frommail,
                            DateSent = mm.DateSent,
                            Subject = mm.Subject,
                            Distributor = mm.Distributor,
                            ConfirmName = mm.ConfirmName
                        };

            return query.ToList();
        }


        public List<MessageMails> Delete(string MessageId, string packageCode = null, string fromdate = null, string todate = null, string Distributor = null, string customerName = null, string taxcode = null, string mobile = null, string email = null, int? confrim = 3, int pageSize = int.MaxValue, int pageIndex = 0)
        {
            _context.MessageMail_Delete(MessageId);
            return GetMessge(packageCode: packageCode, fromdate: fromdate, todate: todate, Distributor: Distributor,
                customerName: customerName, taxcode: taxcode, mobile: mobile, email: email);
        }
    }
}